package burubaka.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slim3.datastore.Datastore;

import burubaka.BurubakaConstants;
import burubaka.common.BurubakaUtil;
import burubaka.meta.MarkSheetMeta;
import burubaka.model.BetTemplateBody;
import burubaka.model.Handicapping;
import burubaka.model.MarkSheet;
import burubaka.model.RaceInfo;
import burubaka.model.Tipster;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Transaction;

public class MarkSheetService {

	private MarkSheetMeta meta = new MarkSheetMeta();

	private RaceInfoService raceInfoService = new RaceInfoService();
	private BetTemplateService betTemplateService = new BetTemplateService();
	private HandicappingService handicappingService = new HandicappingService();
	private TipsterService tipsterService = new TipsterService();

	/**
	 * キー検索
	 * 
	 * @param key
	 * @return List<Key>
	 */
	public List<MarkSheet> findByAncKey(Key anckey) {
		// return Datastore.query(MarkSheet.class,
		// anckey).sort(this.meta.betClass.asc).asList();
		return Datastore.query(MarkSheet.class, anckey).asList();
	}

	/**
	 * キー検索
	 * 
	 * @param key
	 * @return List<Key>
	 */
	public List<Key> getKeyListByKey(Key key) {
		return Datastore.query(MarkSheet.class, key).asKeyList();
	}

	/**
	 * 登録
	 * 
	 * @param model
	 * @return MarkSheet
	 */
	public MarkSheet regist(MarkSheet model) {
		Transaction tx = Datastore.beginTransaction();
		Datastore.put(model);
		tx.commit();
		return model;
	}

	/**
	 * 登録
	 * 
	 * @param model
	 * @param ancKey
	 * @return boolean
	 */
	public boolean regist(List<MarkSheet> list, Key ancKey) {

		Transaction tx = Datastore.beginTransaction();

		Datastore.delete(getKeyListByKey(ancKey));

		for (MarkSheet model : list) {
			Key childKey = Datastore.allocateId(ancKey, MarkSheet.class);
			if (childKey != null) {
				model.setKey(childKey);
			}
		}
		Datastore.put(list);
		tx.commit();

		return true;
	}

	/**
	 * マークシート登録
	 * 
	 * @return List<MarkSheet>
	 */
	public List<MarkSheet> registMarkSheet() {
		Tipster tipster = tipsterService.getTipster();
		return registMarkSheet(tipster);
	}

	/**
	 * マークシート登録
	 * 
	 * @return List<MarkSheet>
	 */
	public List<MarkSheet> registMarkSheet(Tipster tipster) {

		// 現在情報取得
		RaceInfo raceInfo = raceInfoService.getCurrentRaceInfo();
		// まだ本登録されていない場合は何もしない
		if (raceInfo == null || raceInfo.getProgress() < BurubakaConstants.PROGRESS_RACECARD) {
			return null;
		}

		// 投票が締め切られていた場合は何もしない
		if (BurubakaUtil.isOverDeadline(raceInfo)) {
			return null;
		}

		Handicapping handicapping = handicappingService.getHandicapping(tipster.getKey(), raceInfo.getRaceDate());
		if (handicapping == null) {
			return null;
		}

		Map<Integer, String> hdMap = new HashMap<Integer, String>();
		hdMap.put(handicapping.getHorseNo1(), handicapping.getHorseName1());
		hdMap.put(handicapping.getHorseNo2(), handicapping.getHorseName2());
		hdMap.put(handicapping.getHorseNo3(), handicapping.getHorseName3());
		hdMap.put(handicapping.getHorseNo4(), handicapping.getHorseName4());
		hdMap.put(handicapping.getHorseNo5(), handicapping.getHorseName5());
		hdMap.put(handicapping.getHorseNo6(), handicapping.getHorseName6());

		// 賭け金テンプレート取得
		List<BetTemplateBody> tempList = betTemplateService.findBetTemplateBodyByAncKey(tipster.getKey());
		List<MarkSheet> list = new ArrayList<MarkSheet>();
		for (BetTemplateBody temp : tempList) {
			MarkSheet marksheet = new MarkSheet();
			// 馬連
			if (BurubakaConstants.BET_CLASS_QUINELLA[0].equals(temp.getBetClass())) {
				int temp1 = getHorseNo(temp.getMark1(), handicapping);
				int temp2 = getHorseNo(temp.getMark2(), handicapping);
				marksheet.setMark(getMark(true, temp1, temp2));
				marksheet.setHorseMark(getHorseMark(hdMap, true, temp1, temp2));
				marksheet.setBetClass(BurubakaConstants.BET_CLASS_QUINELLA[0]);
				marksheet.setBetClassName(BurubakaConstants.BET_CLASS_QUINELLA[1]);
			}
			// 馬単
			if (BurubakaConstants.BET_CLASS_EXACTA[0].equals(temp.getBetClass())) {
				int temp1 = getHorseNo(temp.getMark1(), handicapping);
				int temp2 = getHorseNo(temp.getMark2(), handicapping);
				marksheet.setMark(getMark(false, temp1, temp2));
				marksheet.setHorseMark(getHorseMark(hdMap, false, temp1, temp2));
				marksheet.setBetClass(BurubakaConstants.BET_CLASS_EXACTA[0]);
				marksheet.setBetClassName(BurubakaConstants.BET_CLASS_EXACTA[1]);
			}
			// 3連複
			if (BurubakaConstants.BET_CLASS_TRIO[0].equals(temp.getBetClass())) {
				int temp1 = getHorseNo(temp.getMark1(), handicapping);
				int temp2 = getHorseNo(temp.getMark2(), handicapping);
				int temp3 = getHorseNo(temp.getMark3(), handicapping);
				marksheet.setMark(getMark(true, temp1, temp2, temp3));
				marksheet.setHorseMark(getHorseMark(hdMap, true, temp1, temp2, temp3));
				marksheet.setBetClass(BurubakaConstants.BET_CLASS_TRIO[0]);
				marksheet.setBetClassName(BurubakaConstants.BET_CLASS_TRIO[1]);
			}
			// 3連単
			if (BurubakaConstants.BET_CLASS_TRIFECTA[0].equals(temp.getBetClass())) {
				int temp1 = getHorseNo(temp.getMark1(), handicapping);
				int temp2 = getHorseNo(temp.getMark2(), handicapping);
				int temp3 = getHorseNo(temp.getMark3(), handicapping);
				marksheet.setMark(getMark(false, temp1, temp2, temp3));
				marksheet.setHorseMark(getHorseMark(hdMap, false, temp1, temp2, temp3));
				marksheet.setBetClass(BurubakaConstants.BET_CLASS_TRIFECTA[0]);
				marksheet.setBetClassName(BurubakaConstants.BET_CLASS_TRIFECTA[1]);
			}
			marksheet.setWager(temp.getWager());
			list.add(marksheet);
		}

		regist(list, handicapping.getKey());

		return list;
	}

	/**
	 * 印から馬番を取得する
	 * 
	 * @param mark
	 * @param handicapping
	 * @return 馬番
	 */
	private int getHorseNo(String mark, Handicapping handicapping) {

		if (BurubakaConstants.MARK_DOUBLE_CIRCLE.equals(mark)) {
			return handicapping.getHorseNo1();
		}
		if (BurubakaConstants.MARK_CIRCLE.equals(mark)) {
			return handicapping.getHorseNo2();
		}
		if (BurubakaConstants.MARK_BLACK_TRIANGULAR.equals(mark)) {
			return handicapping.getHorseNo3();
		}
		if (BurubakaConstants.MARK_TRIANGULAR.equals(mark)) {
			return handicapping.getHorseNo4();
		}
		if (BurubakaConstants.MARK_X.equals(mark)) {
			return handicapping.getHorseNo5();
		}
		if (BurubakaConstants.MARK_STAR.equals(mark)) {
			return handicapping.getHorseNo6();
		}

		return 0;
	}

	private String getMark(boolean sortFlag, int... marks) {
		String ret = "";
		if (sortFlag) {
			Arrays.sort(marks);
		}
		for (int mark : marks) {
			String temp = String.valueOf(mark);
			ret = ret + "-" + temp;
		}
		return ret.substring(1);
	}

	private String getHorseMark(Map<Integer, String> map, boolean sortFlag, int... marks) {
		String ret = "";
		if (sortFlag) {
			Arrays.sort(marks);
		}
		for (int mark : marks) {
			String temp = String.valueOf(mark);
			String horseName = map.get(mark);
			ret = ret + "-" + temp + "：" + horseName + " ";
		}
		return ret.substring(1);
	}
}
